﻿using System;
using System.IO;

//第三方dll
using DreamCube.Foundation.CompressLib.Zip;
using DreamCube.Foundation.CompressLib.Checksums;

namespace DreamCube.Foundation.CompressLib
{
    /// <summary>
    /// 支持递归压缩文件夹
    /// </summary>
    public static class MyZip
    {
        #region 压缩文件夹,支持递归

        #region "公共方法"

        /// <summary>  
        ///　压缩文件夹  
        /// </summary>  
        /// <param name="dir">待压缩的文件夹</param>  
        /// <param name="targetFileName">压缩后文件路径（包括文件名）</param>  
        /// <param name="recursive">是否递归压缩</param>  
        /// <returns></returns>  
        public static Boolean Compress(String dir, String targetFileName, Boolean recursive, CompressOper compressOper)
        {
            //如果已经存在目标文件，询问用户是否覆盖  
            if (compressOper == CompressOper.Replace && File.Exists(targetFileName))
                File.Delete(targetFileName);

            //不递归压缩
            if (!recursive) return CompressDirectory(dir, targetFileName);

            FileStream zipFile = File.Create(targetFileName);
            using (ZipOutputStream zipStream = new ZipOutputStream(zipFile))
            {
                if (dir.EndsWith("\\")) dir = dir.Substring(0, dir.Length - 1);
                if (dir != String.Empty) _CompressFolder(dir, zipStream, dir);
            }

            if (File.Exists(targetFileName))
                return true;
            else
                return false;
        }

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="fileName">文件路径</param>
        /// <param name="targetFileName">压缩文件的目标文件名</param>
        /// <returns></returns>
        public static Boolean Compress(String fileName, String targetFileName, CompressOper compressOper)
        {
            //如果已经存在目标文件，询问用户是否覆盖  
            if (compressOper == CompressOper.Replace && File.Exists(targetFileName))
                File.Delete(targetFileName);

            FileStream zipFile = File.Create(targetFileName);
            using (ZipOutputStream zipStream = new ZipOutputStream(zipFile))
            {
                String fileFolder = fileName.Substring(0, fileName.Length - fileName.LastIndexOf("\\"));
                String folderName = fileFolder.Substring(fileFolder.LastIndexOf("\\") + 1);
                if (File.Exists(fileName))
                    _AddFile(fileName, zipStream, folderName);
            }

            if (File.Exists(targetFileName))
                return true;
            else
                return false;
        }

        #endregion

        #region "私有方法"

        /// <summary>
        /// 非递归压缩目录
        /// </summary>
        /// <param name="dir">目录路径</param>
        /// <param name="targetFileName">生成的压缩文件名</param>
        /// <returns></returns>
        private static Boolean CompressDirectory(String dir, String targetFileName)
        {
            using (ZipOutputStream s = new ZipOutputStream(File.Create(targetFileName)))
            {
                String[] filenames = Directory.GetFiles(dir);
                s.SetLevel(6);
                Byte[] buffer = new Byte[1024 * 10];
                foreach (String file in filenames)
                {
                    //打开压缩文件  
                    using (FileStream fs = File.OpenRead(file))
                    {
                        Int32 readLength;
                        ZipEntry entry = new ZipEntry(file);
                        entry.DateTime = DateTime.Now;
                        entry.Size = fs.Length;
                        s.PutNextEntry(entry);
                        do
                        {
                            readLength = fs.Read(buffer, 0, buffer.Length);
                            if (readLength > 0) s.Write(buffer, 0, readLength);
                        } while (readLength > 0);
                    }
                }
            }
            return true;
        }

        /// <summary>  
        /// 压缩某个子文件夹  
        /// </summary>  
        /// <param name="basePath"></param>  
        /// <param name="zips"></param>  
        /// <param name="zipfolername"></param>       
        private static void _CompressFolder(String basePath, ZipOutputStream zips, String zipfolername)
        {
            String[] names = Directory.GetFiles(basePath);
            foreach (String fileName in names)
            {
                _AddFile(fileName, zips, zipfolername);
            }

            names = Directory.GetDirectories(basePath);
            foreach (String folderName in names)
            {
                _CompressFolder(folderName, zips, zipfolername);
            }
        }

        /// <summary>  
        ///　压缩某个子文件  
        /// </summary>  
        /// <param name="fileName"></param>  
        /// <param name="zips"></param>  
        /// <param name="zipfolername"></param>  
        private static void _AddFile(String fileName, ZipOutputStream zips, String zipfolername)
        {
            if (File.Exists(fileName)) _CreateZipFile(fileName, zips, zipfolername);
        }

        /// <summary>  
        /// 压缩单独文件  
        /// </summary>  
        /// <param name="fileToZip"></param>  
        /// <param name="zips"></param>  
        /// <param name="zipfolername"></param>  
        private static void _CreateZipFile(String fileToZip, ZipOutputStream zips, String zipfolername)
        {
            using (FileStream streamToZip = new FileStream(fileToZip, FileMode.Open, FileAccess.Read))
            {
                String entryName = fileToZip.Substring(fileToZip.IndexOf(zipfolername) + zipfolername.Length + 1);
                ZipEntry zipEn = new ZipEntry(entryName);
                zips.PutNextEntry(zipEn);
                Byte[] buffer = new Byte[1024 * 10];
                Int32 read;
                do
                {
                    read = streamToZip.Read(buffer, 0, buffer.Length);
                    if (read > 0) zips.Write(buffer, 0, read);
                }
                while (read > 0);
            }
        }

        #endregion

        #endregion

        #region "解压缩目录"

        /// <summary>  
        /// 解压缩目录  
        /// </summary>  
        /// <param name="zipedFilePath">被解压的文件</param> 
        /// <param name="outputDir">解压后的存放目录</param>  
        /// <param name="password">解压密码</param>  
        /// <param name="overwrite">解压覆盖同名文件（默认是true）</param>  
        public static void UnZip(String zipedFilePath, String outputDir, String password = "", Boolean overwrite = true)
        {
            if (String.IsNullOrEmpty(outputDir)) outputDir = Directory.GetCurrentDirectory();
            using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipedFilePath)))
            {
                //判断Password  
                if (password != null && password.Length > 0) zipStream.Password = password;
                ZipEntry zipEntry = null;
                while ((zipEntry = zipStream.GetNextEntry()) != null)
                {
                    String directoryName = Path.GetDirectoryName(zipEntry.Name);
                    String fileName = Path.GetFileName(zipEntry.Name);

                    if (!String.IsNullOrEmpty(directoryName)) Directory.CreateDirectory(outputDir + @"\" + directoryName);

                    if (!String.IsNullOrEmpty(fileName))
                    {
                        if (zipEntry.CompressedSize == 0) break;
                        if (zipEntry.IsDirectory)//如果压缩格式为文件夹方式压缩  
                        {
                            directoryName = Path.GetDirectoryName(outputDir + @"\" + zipEntry.Name);
                            Directory.CreateDirectory(directoryName);
                        }
                        else
                        {
                            //2012-5-28修改，支持单个文件压缩时自己创建目标文件夹
                            if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
                        }

                        byte[] buffer = new byte[2048];
                        using (FileStream stream = File.Create(outputDir + @"\" + zipEntry.Name))
                        {
                            while (true)
                            {
                                int size = zipStream.Read(buffer, 0, buffer.Length);
                                if (size > 0)
                                {
                                    stream.Write(buffer, 0, size);
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        #endregion
    }
}
